package com.qen.common;

import cn.hutool.core.util.StrUtil;
import com.qen.constant.DataBaseConstants;
import com.qen.enums.SqlKeyword;
import com.qen.wrapper.LambdaWrapper;
import org.beetl.sql.clazz.ClassDesc;
import org.beetl.sql.clazz.NameConversion;
import org.beetl.sql.clazz.TableDesc;
import org.beetl.sql.clazz.kit.BeanKit;

import java.util.Objects;
import java.util.Optional;

/**
 * @author licz
 * @since 1.0.0
 */
@SuppressWarnings("DuplicatedCode")
public class WrapperUtils {

    public static <T> String buildSubSqlByWrapper(Class<T> clazz, LambdaWrapper<T> wrapper, String alias) {
        return String.format("%s AS %s", buildUnionSqlByWrapper(clazz, wrapper), alias);
    }

    public static String buildUnionSqlByWrapper(Class<?> clazz, LambdaWrapper<?> wrapper) {
        return buildUnionSqlByWrapper(clazz, true, wrapper);
    }

    public static String buildUnionSqlByWrapper(Class<?> clazz, boolean brackets, LambdaWrapper<?> wrapper) {
        ClassDesc classDesc = BeetlUtils.getSQLManager().getClassDesc(clazz);
        TableDesc tableInfo = TableInfoHelper.getTableInfo(clazz);
        String first = Optional.ofNullable(wrapper.getSqlFirst()).orElse(StrUtil.EMPTY);
        boolean hasWhere = false;
        String entityWhere = getEntitySql(classDesc, tableInfo, wrapper);
        if (StrUtil.isNotBlank(entityWhere)) {
            hasWhere = true;
        }
        String mainLogic = mainLogic(hasWhere, clazz, wrapper);
        if (StrUtil.isNotBlank(mainLogic)) {
            hasWhere = true;
        }
        String subLogic = subLogic(hasWhere, wrapper);
        if (StrUtil.isNotBlank(subLogic)) {
            hasWhere = true;
        }
        String and = StrUtil.SPACE + SqlKeyword.AND.getSqlSegment() + StrUtil.SPACE;
        String where = StrUtil.SPACE + SqlKeyword.WHERE.getSqlSegment() + StrUtil.SPACE;
        String sqlSegment = (wrapper.getSqlSegment() != null && StrUtil.isNotBlank(wrapper.getSqlSegment())) ?
                ((wrapper.isEmptyOfNormal() ? StrUtil.EMPTY : (hasWhere ? and : where)) + wrapper.getSqlSegment()) : StrUtil.EMPTY;
        String sqlComment = Optional.ofNullable(wrapper.getSqlComment()).orElse(StrUtil.EMPTY);
        String sqlUnion = wrapper.getUnionSql();
        StringBuilder sb = new StringBuilder(StrUtil.SPACE)
                .append(first)
                .append(StrUtil.SPACE)
                .append(SqlKeyword.SELECT.getSqlSegment())
                .append(StrUtil.SPACE)
                .append(wrapper.getSqlSelect())
                .append(StrUtil.SPACE)
                .append(SqlKeyword.FROM.getSqlSegment())
                .append(StrUtil.SPACE)
                .append(wrapper.getTableName(tableInfo.getName()))
                .append(StrUtil.SPACE)
                .append(wrapper.getAlias())
                .append(StrUtil.SPACE)
                .append(wrapper.getFrom())
                .append(StrUtil.SPACE)
                .append(mainLogic)
                .append(StrUtil.SPACE)
                .append(subLogic)
                .append(StrUtil.SPACE)
                .append(sqlSegment)
                .append(StrUtil.SPACE)
                .append(sqlComment)
                .append(StrUtil.SPACE)
                .append(sqlUnion)
                .append(StrUtil.SPACE);
        if (brackets) {
            sb.insert(0, "(").append(")");
        }
        return sb.toString();
    }

    private static <T> String formatParam(LambdaWrapper<T> wrapper, Object param) {
        final String genParamName = DataBaseConstants.WRAPPER_PARAM + wrapper.getParamNameSeq().incrementAndGet();
        final String paramStr = wrapper.getParamAlias() + ".paramNameValuePairs." + genParamName;
        wrapper.getParamNameValuePairs().put(genParamName, param);
        return SqlUtils.safeParam(paramStr, null);
    }

    private static String getEntitySql(ClassDesc classDesc, TableDesc tableDesc, LambdaWrapper<?> wrapper) {
        Object obj = wrapper.getEntity();
        if (Objects.isNull(obj)) {
            return StrUtil.EMPTY;
        }
        NameConversion nc = BeetlUtils.getSQLManager().getNc();
        StringBuilder sb = new StringBuilder(StrUtil.EMPTY);
        for (String attr : classDesc.getAttrs()) {
            Object val = BeanKit.getBeanProperty(obj, (String) attr);
            if (Objects.isNull(val)) {
                continue;
            }
            String col = nc.getColName(classDesc.getTargetClass(), attr);
            sb.append(StrUtil.SPACE)
                    .append(SqlKeyword.AND.getSqlSegment())
                    .append(StrUtil.SPACE)
                    .append(wrapper.getTableList().getPrefixByClass(obj.getClass())).append(StrUtil.DOT)
                    .append(col)
                    .append(SqlKeyword.EQ.getSqlSegment())
                    .append(formatParam(wrapper, val));

        }
        //条件不为空 加上 where
        if (sb.length() > 0) {
            sb.delete(0, 4);
            sb.insert(0, SqlKeyword.WHERE.getSqlSegment());
        }
        return sb.toString();
    }

    private static String mainLogic(boolean hasWhere, Class<?> clazz, LambdaWrapper<?> wrapper) {
        if (!wrapper.getLogicSql()) {
            return StrUtil.EMPTY;
        }
        String info = LogicInfoUtils.getLogicInfo(null, clazz, true, wrapper.getAlias());
        if (StrUtil.isNotBlank(info)) {
            if (hasWhere) {
                return SqlKeyword.AND.getSqlSegment() + info;
            }
            return SqlKeyword.WHERE.getSqlSegment() + info.substring(4);
        }
        return StrUtil.EMPTY;
    }

    private static String subLogic(boolean hasWhere, LambdaWrapper<?> wrapper) {
        String sql = wrapper.getSubLogicSql();
        if (StrUtil.isNotBlank(sql)) {
            if (hasWhere) {
                return sql;
            }
            return StrUtil.SPACE + SqlKeyword.WHERE.getSqlSegment() + StrUtil.SPACE + sql.substring(4);
        }
        return StrUtil.EMPTY;
    }
}
